#ifndef VORONOI_RENDERER_H
#define VORONOI_RENDERER_H
#include <vector>
#include "../../glutil/PortableGL.h"
#include "../../glutil/FBO.h"
#include "../../glutil/shaderUtils.h"
#include "../../util/NTuple.h"
#include "VoronoiParser.h"
#include "../../geom/Point3D.h"
#include <cmath>
#include <map>
#include <QThread>
#include "../../geom/TerrainModel.h"
#include "../mainwidget.h"
#include <QGLContext>
class VoronoiGenerationThread;

namespace voronoi
{

	class VoronoiRenderer
	{
		public:
            VoronoiRenderer(const geom::TerrainPointsList &points, int width, int height);

            void generateAndParse(float cellsize, float depthDivisor, float maxDensity, VoronoiGenerationThread * thread);
            void getTriangulated(std::vector<util::Triplet<unsigned int> > * triangles, std::map<unsigned int, geom::Vector3D> * normals);

			virtual ~VoronoiRenderer();


		private:
			void render(double minx, double maxx, double miny, double maxy, double squareSide, float depthDivisor);
			unsigned int * getRenderedImage();

			std::set<Face> m_parsedFaces;

			glutil::ShaderProgram * m_shader;
			GLfloat * renderedImage;
			unsigned int * convertedImage;
            const geom::TerrainPointsList &m_points;
			int m_width;
			int m_height;
			glutil::FBO m_fbo;
			int numPoints;
			bool imageRendered;

			class PointComparator
			{
				public:
                    PointComparator(const geom::TerrainPointsList &points, geom::Point3D center) : m_points(points),m_center(center) {}
					double angleToPoint(const geom::Point3D &p) const 
					{
						double vec[2] = {p.x - m_center.x,  p.z - m_center.z};
						double modulus = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
						double angleToP = atan2(vec[1]/modulus,vec[0]/modulus);
						//if(angleToP<0)  angleToP +=2*M_PI;
						return angleToP;
					}   
					bool operator()(const unsigned int &p1, const unsigned int &p2) const
					{   
                        const geom::Point3D &pp1 = m_points.at(p1).p;   const geom::Point3D &pp2 = m_points.at(p2).p;
						double atopp1 = angleToPoint(pp1);      double atopp2 = angleToPoint(pp2);
						return atopp1< atopp2;
					}
				private: 
                    const geom::TerrainPointsList &m_points;
					geom::Point3D m_center;
			};             
	};
}
class VoronoiGenerationThread : public QThread
{
    Q_OBJECT
        public:
    VoronoiGenerationThread(MainWidget * parent, voronoi::VoronoiRenderer * renderer,
                            float cellsize, float depthdivisor, float maxDensity)
    : m_parent(parent), m_renderer(renderer), m_cellSize(cellsize), m_depthDivisor(depthdivisor), m_maxDensity(maxDensity),m_mustEnd(false)//,m_context(QGLFormat())
    {

    }
    void doEmitStatusUpdate(float percentageComplete, int imagesFinished, int totalImages)
    {
        emit statusUpdate(percentageComplete,imagesFinished, totalImages);
    }
    bool mustEnd()
    {
        return m_mustEnd;
    }
        public slots:
    void tryToEnd();
        signals:
    void statusUpdate(float percentageComplete , int imagesFinished, int totalImages);

        protected:
    void run();
    MainWidget * m_parent;
    voronoi::VoronoiRenderer * m_renderer;
    float m_cellSize;
    float m_depthDivisor;
    float m_maxDensity;
    bool m_mustEnd;
    //QGLContext m_context;
};

#endif
